package cuckoo.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;

import cuckoo.aop.intercept.AfterInterceptor;
import cuckoo.aop.intercept.BeforeInterceptor;
import cuckoo.aop.intercept.ExceptionInterceptor;
import cuckoo.aop.intercept.Interceptor;

public class ProxyHandler implements InvocationHandler {
	private Map<Method, Set<Interceptor>> map;
	private Object bean;

	public ProxyHandler(Map<Method, Set<Interceptor>> map, Object bean) {
		this.map = map;
		this.bean = bean;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object obj = null;

		Method realMethod = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
		try {
			doBefore(realMethod, args);
			obj = method.invoke(bean, args);
			doAfter(realMethod, args);
		} catch (Exception e) {
			doException(realMethod, args, e);
		}
		return obj;
	}

	private void doBefore(Method method, Object[] args) {
		Set<Interceptor> set = map.get(method);
		if (set == null)
			return;
		for (Interceptor interceptor : set) {
			if (interceptor instanceof BeforeInterceptor) {
				((BeforeInterceptor) interceptor).before(method, args);
			}
		}
	}

	private void doAfter(Method method, Object[] args) {
		Set<Interceptor> set = map.get(method);
		if (set == null)
			return;
		for (Interceptor interceptor : set) {
			if (interceptor instanceof AfterInterceptor) {
				((AfterInterceptor) interceptor).after(method, args);
			}
		}
	}

	private void doException(Method method, Object[] args, Exception e) {
		Set<Interceptor> set = map.get(method);
		if (set == null)
			return;
		for (Interceptor interceptor : set) {
			if (interceptor instanceof ExceptionInterceptor) {
				((ExceptionInterceptor) interceptor).exception(method, args, e);
			}
		}
	}
}
